# -*-coding: utf-8 -*-
"""
    @Theme   : User's Commands
    @Time    : 2024/7/7 14:17
    @Author  : YamFish
    @Url     : https://www.zhihu.com/people/yamfish
"""
import hashlib
import random

import click
import redis
import pymongo
from faker import Faker
from bson import ObjectId
from werkzeug.security import generate_password_hash

fake = Faker()


def register_cmd(app):
    @app.cli.command()
    @click.option('--user', '-u', default=15, help='registered users, default is 15.')
    @click.option('--question', '-q', default=15, help='questions count, default is 15.')
    @click.option('--drop', is_flag=True, help='drop all and then create all')
    def init_db(user, question, drop):
        """Initialize the database."""
        db = pymongo.MongoClient(app.config['MONGODB_URI']).get_database(app.config['MONGODB_DATABASE'])
        if drop:
            click.confirm('This operation will delete the database, do you want to continue?', abort=True)
            db.user.drop()
            db.question.drop()
            db.answer.drop()
            db.vote.drop()
            click.echo('Drop tables ok.')

        users = []
        for _ in range(user):
            row = {
                'user': fake.name(),
                'password_hash': generate_password_hash('111111'),
                'register_time': fake.date_time_this_month(before_now=True)
            }
            users.append(row)
        db.user.insert_many(users)

        questions = []
        for _ in range(question):
            row = {
                'author': random.choice(users)['user'],
                'title': fake.sentence(6).capitalize()[:-1] + '?',
                'detail': fake.paragraph(3),
                'ask_time': fake.date_time_this_year(before_now=True),
            }
            questions.append(row)
        db.question.insert_many(questions)

        answers = []
        question_ids = list(db.question.find({}, {'_id': 1}))
        for question_id in question_ids:
            for user_info in users:
                row = {
                    'author': user_info['user'],
                    'question_id': ObjectId(question_id['_id']),
                    'answer': fake.paragraph(5),
                    'answer_time': fake.date_time_this_year(),
                }
                answers.append(row)
        db.answer.insert_many(answers)

        votes = []
        answer_ids = list(db.answer.find({}, {'_id': 1}))
        for question_id in question_ids:
            for user_info in users:
                row = {
                    'doc_type': 'question',
                    'doc_id': ObjectId(question_id['_id']),
                    'value': random.choice([-1, 1]),
                    'user': user_info['user'],
                    'vote_time': fake.date_time_this_year()
                }
                votes.append(row)
        db.vote.insert_many(votes)

        votes.clear()
        for answer_id in answer_ids:
            for user_info in users:
                row = {
                    'doc_type': 'answer',
                    'doc_id': ObjectId(answer_id['_id']),
                    'value': random.choice([-1, 1]),
                    'user': user_info['user'],
                    'vote_time': fake.date_time_this_year()
                }
                votes.append(row)
        db.vote.insert_many(votes)
        click.echo('Initialized database ok.')

    @app.cli.command()
    @click.option('--drop', is_flag=True, help='drop all and then create all')
    def load_redis(drop):
        db = pymongo.MongoClient(app.config['MONGODB_URI']).get_database(app.config['MONGODB_DATABASE'])
        client = redis.Redis(host=app.config['REDIS_HOST'], password=app.config['REDIS_PASSWORD'])
        if drop:
            keys = [key.decode() for key in client.keys(r'qa_system:*')]
            if keys:
                click.echo(f'Delete following keys: {"、".join(keys)}')
                client.delete(*keys)

        # qa_system:question:vote
        for row in db.question.find({}, {'_id': 1}):
            question_id = row['_id']
            question_votes = db.vote.find({'doc_type': 'question', 'doc_id': question_id}, {'value': 1})
            votes = sum([value['value'] for value in question_votes])
            client.zadd(app.config['REDIS_KEY_QUESTION_VOTE'], {str(question_id): votes})

        # qa_system:answer:<question_id>:vote
        for row in db.answer.find({}, {'_id': 1, 'question_id': 1}):
            answer_id = row['_id']
            question_id = row['question_id']
            key = app.config['REDIS_KEY_ANSWER_VOTE'].format(question_id)
            answer_votes = db.vote.find({'doc_type': 'answer', 'doc_id': answer_id}, {'value': 1})
            votes = sum([value['value'] for value in answer_votes])
            client.zadd(key, {str(answer_id): votes})

        # qa_system:user:answer
        for row in db.answer.find({}, {'_id': 0, 'question_id': 1, 'author': 1}):
            key = hashlib.md5((row['author'] + str(row['question_id'])).encode('utf-8')).hexdigest()
            client.hset(app.config['REDIS_KEY_USER_ANSWER'], key, '1')

        # qa_system:user:vote
        votes = db.vote.aggregate([
            {
                '$group': {
                    '_id': {'user': '$user', 'doc_id': '$doc_id'},
                    'value': {'$sum': '$value'}
                }
            }
        ])
        for row in votes:
            user = row['_id']['user']
            question_or_answer_id = str(row['_id']['doc_id'])
            value = row['value']
            key = hashlib.md5((user + question_or_answer_id).encode('utf-8')).hexdigest()
            client.hset(app.config['REDIS_KEY_USER_VOTE'], key, value)

        click.echo('Initialized Redis ok.')
